beat-generatorによるBeats開発
はじめに
藤本です。
Elastic{ON}2016はエキサイティングでした。今回はElastic{ON}のBeatsセッションで紹介されていたBeats開発ツールのbeat-generatorを試してみましたのでご紹介します。
概要
BeatsはGo言語で開発された軽量なData Shipperです。様々なデータに対応したBeatsが開発されており、Elastic{ON}2016会期時点では4つのオフィシャルBeats、14つのコミュニティBeatsが公開されています。
Beatsに関しては以下のブログをご参照ください。
Beatsは、公式ドキュメントに開発手順が公開されており、手順に則れば、独自Beatsを開発することができました。ただ、Go言語と英語が分からない私にはハードルが高かったです。
今回はElasticのgithubで公開されているbeat-generatorを利用して、独自Beatsを開発してみましょう。
Beatsの実装の細かいところに関しては以下のブログが非常に参考になります。
Beatsのつくりかた - ヒープとGCを取得するJstatbeatsを実装してみた
上のブログと比較して、beat-generatorによって短縮される箇所は名称の自動補完、必要最小限のテンプレートから開発をスタートできる、パッケージ管理、バイナリ・設定ファイルの生成、といったところでしょうか。
やってみた
今回のサンプルでは、Elasticsearchのインデックスのドキュメント数をカウントするBeatsを開発します。
事前準備
Cookiecutterインストール
Beatsのテンプレート作成にCookiecutterを利用します。
cookiecutterはpipやbrewでインストール可能です。
# pip install cookiecutter
or
# brew install cookiecutter
glideインストール
beat-generatorはパッケージ管理にglideを利用します。
glideはbrewでインストール可能です。
# brew install glide
Beatsテンプレート作成
Beatsの雛形をbeat-generatorからcookiecutterで作成します。
projectnameにDoccountbeat
、github_nameにGithub Account
を指定します。
# cookiecutter https://github.com/elastic/beat-generator.git Cloning into 'beat-generator'... remote: Counting objects: 157, done. remote: Compressing objects: 100% (10/10), done. remote: Total 157 (delta 2), reused 0 (delta 0), pack-reused 147 Receiving objects: 100% (157/157), 25.41 KiB | 0 bytes/s, done. Resolving deltas: 100% (59/59), done. Checking connectivity... done. project_name [Examplebeat]: Doccountbeat github_name [your-github-name]: s-fujimoto beat [doccountbeat]: beat_path [github.com/s-fujimoto]: full_name [Firstname Lastname]: Shinji Fujimoto
以下のようなファイルが作成されます。
いくつかのファイルが作成されていますが、最低限実装すべきファイルは*を付けた3ファイルだけとなります。
(バージョン情報を埋め込む場合はmain.goにも設定が必要です)
tree doccountbeat doccountbeat ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── beater │ └── doccountbeat.go * ├── config │ └── config.go * ├── docs │ └── index.asciidoc ├── etc │ ├── beat.yml * │ ├── doccountbeat.template.json │ └── fields.yml ├── glide.yaml ├── main.go ├── main_test.go └── tests └── system ├── config │ └── doccountbeat.yml.j2 ├── doccountbeat.py ├── requirements.txt └── test_base.py 7 directories, 17 files
次にパッケージをインストールします。
# cd doccountbeat # make init glide update --no-recursive [INFO] Downloading dependencies. Please wait... [INFO] Fetching updates for github.com/elastic/beats. [INFO] Setting version for github.com/elastic/beats to ae30528774fffa5879392388f651286785118d38. [WARN] Skipping lockfile generation because full dependency tree is not being calculated make update bash ./vendor/github.com/elastic/beats/libbeat/scripts/update.sh doccountbeat github.com/s-fujimoto/doccountbeat ./vendor/github.com/elastic/beats/libbeat Beat name: doccountbeat Beat path: ../doccountbeat Start modifying beat Update config file Update fields fields.yml file is empty. fields.asciidoc cannot be generated. fields.yml is empty. Cannot generate template. git init Initialized empty Git repository in /Users/fujimoto.shinji/Techs/go/src/github.com/s-fujimoto/doccountbeat/.git/ git add .
設定ファイル
BeatsはYaml形式を設定ファイルに利用します。テンプレートのYamlファイルは実行間隔となるperiodのみが設定値に用意されています。
今回のDoccountbeatでは設定ファイルにて、ドキュメント数を取得する対象となるindex名を指定できるようにします。
Yamlファイル
Yamlファイルにフィールドを追加します。
etc/beat.yml
# vi etc/beat.yml doccountbeat: period: 1s index: logstash-* // index名となるフィールドを追加
設定ファイルのオブジェクト実装
Yamlファイルとマッピングする構造体にフィールドを追加します。
config/config.go
# vi config/config.go (略) type DoccountbeatConfig struct { Period string `yaml:"period"` Index string `yaml:"index"` // index名となるフィールドを追加 }
インデックスからドキュメント数を取得する実装を追加
メインとなる処理を実装します。既に実装が用意されていますので、``Run```関数に記録したい値を取得する処理、MapにKey/Valueを追加するだけです。簡単ですね。
beater/doccountbeat.go
# vi beater/doccountbeat.go (略) func (bt *Doccountbeat) Run(b *beat.Beat) error { (略) ++ url := "http://localhost:9200/" + bt.Configuration.Doccountbeat.Index + "/_count" // ドキュメント数を取得するAPIのURLを生成 ++ resp, _ := http.Get(url) // localhostのElasticsearchへリクエスト ++ body, _ := ioutil.ReadAll(resp.Body) ++ js, _ := simplejson.NewJson(body) // go-simplejsonパッケージにてjsonをパース ++ doc_count, _ := js.Get("count").Int() // レスポンスのJsonからcountキーの値を取得 event := common.MapStr{ "@timestamp": common.Time(time.Now()), "type": b.Name, "counter": counter, ++ "doc_count": doc_count, // 取得したドキュメント数をMapに追加 } b.Events.PublishEvent(event) (略)
コンパイル
設定ファイル、実行ファイルとなるバイナリを生成します。
# make go build # ls -l total 26256 -rw-r--r-- 1 fujimoto.shinji staff 0 3 1 14:41 CONTRIBUTING.md -rw-r--r-- 1 fujimoto.shinji staff 560 3 1 14:41 LICENSE -rw-r--r-- 1 fujimoto.shinji staff 893 3 1 14:41 Makefile -rw-r--r-- 1 fujimoto.shinji staff 1988 3 1 14:41 README.md drwxr-xr-x 3 fujimoto.shinji staff 102 3 1 14:41 beater drwxr-xr-x 3 fujimoto.shinji staff 102 3 1 15:13 config -rwxr-xr-x 1 fujimoto.shinji staff 13398140 3 1 16:38 doccountbeat // 追加 -rw-r--r-- 1 fujimoto.shinji staff 9119 3 1 15:07 doccountbeat.yml // 追加 drwxr-xr-x 4 fujimoto.shinji staff 136 3 1 15:07 docs drwxr-xr-x 5 fujimoto.shinji staff 170 3 1 16:18 etc -rw-r--r-- 1 fujimoto.shinji staff 1676 3 1 16:25 glide.lock -rw-r--r-- 1 fujimoto.shinji staff 237 3 1 15:52 glide.yaml -rw-r--r-- 1 fujimoto.shinji staff 220 3 1 14:41 main.go -rw-r--r-- 1 fujimoto.shinji staff 398 3 1 14:41 main_test.go drwxr-xr-x 3 fujimoto.shinji staff 102 3 1 14:41 tests drwxr-xr-x 3 fujimoto.shinji staff 102 3 1 16:38 vendor
動作確認
実行
設定ファイルにindex名、出力先のElasticsearchホストを指定します。
# vi doccountbeat.yml doccountbeat: period: 1s index: test output: elasticsearch: hosts: ["localhost:9200"]
Kibanaでデータ確認
ラインチャートでデータを確認してみます。
空のインデックスを指定しているので0件のデータがプロットされています。
対象のインデックスにデータを追加します。
# curl -XPOST localhost:9200/test/type -d '{"name":""}' {"_index":"test","_type":"type","_id":"AVMxNrAwSbtYHrUlXJfi","_version":1,"_shards":{"total":2,"successful":1,"failed":0},"created":true}
doc_countが1となりました。取得したデータが送信されています。
まとめ
いかがでしたでしょうか。
beat-generatorを利用することで、簡単に独自Beatsを実装することができました。必要な設定、必要な処理を実装するだけです。Beats/Logstash => Elasticsearch => Kibanaの組み合わせは少ない実装で本当に多くのユースケースを実現することができます。